package io.github.biezhi.elves.thread;

import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;


import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;

import io.github.biezhi.elves.common.Constants;
import io.github.biezhi.elves.ok.http.FastHttpClient;
import io.github.biezhi.elves.qcc.model.CompBasic;
import io.github.biezhi.elves.qcc.model.CompBidding;
import io.github.biezhi.elves.qcc.model.CompQccCrawl;
import io.github.biezhi.elves.service.QccBiddingService;
import io.github.biezhi.elves.utils.StringUtils;

/**
 * 爬取企查查招投标信息线程
 * @author zq
 *
 */
@Component
public class QccBiddingRunnable implements Runnable {
	
	private String qccCookie;
	private List<CompBasic> compBasicList;
	
	
	public QccBiddingRunnable() {
		super();
	}
	public QccBiddingRunnable(String qccCookie,List<CompBasic> compBasicList) {
		this.qccCookie = qccCookie;
		this.compBasicList = compBasicList;
	}

	@Autowired
	private QccBiddingService qccBiddingServiceBean;
	private static QccBiddingService qccBiddingService;
	
	@Bean
	public QccBiddingService getQccBiddingServiceBean(){
		if(qccBiddingServiceBean!=null){
			qccBiddingService = qccBiddingServiceBean;
			return qccBiddingService;
		}
		return null;
	}
	
	private String url = "https://www.qcc.com/";
	
	
	@Override
	public void run() {
			for (CompBasic compBasic : compBasicList) {
				//获取企业id
				Long compId = compBasic.getCompId();
				//获取企业名称
				String compName = compBasic.getCompName();
				System.out.println(compBasic);
				System.out.println(compName);
				
				//获取企业详细url,以及准确的企业名称
				String htmlContentByCompName = getHtmlContentByCompName(compName);
				CompBasic cb = getCompDetailUrl(htmlContentByCompName);
				//企业名称校正为企查查搜索出的第一个企业名称
				compName = cb.getCompName();
				//企业详细url
				String compDetailUrl = cb.getCompDetailUrl();
				//获取企查查信息id
				String qccId = "";
				
				List<CompBidding> compBidList = new ArrayList<CompBidding>();
				if (compDetailUrl != null && compDetailUrl != "" ) {
					qccId = compDetailUrl.substring(compDetailUrl.indexOf("_")+1, compDetailUrl.indexOf("."));
					//通过获取经营状况页面，找出招投标数量
					Integer totalCount = getHtmlContentByParamAndKeyNo("company_getinfos", qccId,compId,compName);
					if (totalCount != 0) {
						//总页数
						Integer totalPage = (int) Math.ceil( (double) totalCount / (double) 10);
						compBidList = getHtmlContentByParamAndKeyNo("company_getinfos", qccId,compId,compName,totalPage);
					}else {
						//表名企查查没有搜索到结果，将表字段更新为爬取异常
						System.out.println("该企业没有招投标项目！企业id==>"+compId);
						qccBiddingService.updateSpiderBidState(compId,2);
						continue;
					}
				}else {
					//表名企查查没有搜索到结果，将表字段更新为爬取异常
					System.out.println("找不到该企业！企业id==>"+compId);
					qccBiddingService.updateSpiderBidState(compId,2);
					continue;
				}
				
				for (CompBidding compBidding : compBidList) {
					//将compBidList插入到数据库
					qccBiddingService.insertSpiderBidData(compBidding);
				}
				//将表字段更新为已爬取
				qccBiddingService.updateSpiderBidState(compId,1);
			}
	}
	
	String proxyIp = Constants.PROXY_IP;
	int proxyPort = Constants.PROXY_PORT;
	//通过get请求获取网页内容
	private String getHtmlContentByCompName(String compName) {
		String result = "";
		sleepTime(10000L);
		try {
			io.github.biezhi.elves.ok.http.Response okHttpResponse;
			okHttpResponse = FastHttpClient
					.newBuilder()
//					.proxy(proxy)
					.build()
					.get()
					.addHeader("cookie", qccCookie)
					.url(url+"search?key="+compName)
					.build()
					.execute();
			System.out.println(url+"search?key="+compName+"qccCookie:"+qccCookie);
			result = okHttpResponse.string();
			if (result.contains("<script>window.location.href='https://www.qcc.com/")
					|| result.contains("user_login_normal")) {
				System.err.println("获取搜索第一条企业过于频繁，休眠30s！" + Thread.currentThread().getName()+"========>"+qccCookie);
				sleepTime(30000L);
				result = getHtmlContentByCompName(compName);
			}
			if(!StringUtils.isNullOrEmpty(result)){
				return result;
			}
		} catch (SocketTimeoutException e) {
			System.err.println("===连接超时，重新调用getHtmlContentByCompName(compName)方法===");
			sleepTime(10000L);
			getHtmlContentByCompName(compName);
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("===其他异常，重新调用getHtmlContentByCompName(compName)方法===");
			sleepTime(10000L);
			getHtmlContentByCompName(compName);
		}
		return result;
	}
	
	//通过get请求和公司详情页面的url获取网页内容
	private String getHtmlContentByCompDetailUrl(String compDetailUrl) {
		String result = "";
		try {
			sleepTime(10000L);
			io.github.biezhi.elves.ok.http.Response okHttpResponse;
			okHttpResponse = FastHttpClient
					.newBuilder()
					.build()
					.get()
					.addHeader("cookie", qccCookie)
					.url(url+compDetailUrl+"?tab=run")
					.build()
					.execute();
			System.out.println(url+compDetailUrl+"#run");
			result = okHttpResponse.string();
			if (result.contains("<script>window.location.href='https://www.qcc.com/")
					|| result.contains("user_login_normal")) {
				System.err.println("操作过于频繁，休眠30s！" + Thread.currentThread().getName()+"========>"+qccCookie);
				sleepTime(30000L);
				result = getHtmlContentByCompDetailUrl(compDetailUrl);
			}
			if(!StringUtils.isNullOrEmpty(result)){
				return result;
			}
		} catch (SocketTimeoutException e) {
			System.err.println("===连接超时，重新调用getHtmlContentByCompDetailUrl(compDetailUrl)方法===");
			sleepTime(10000L);
			getHtmlContentByCompDetailUrl(compDetailUrl);
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("===其他异常，重新调用getHtmlContentByCompDetailUrl(compDetailUrl)方法===");
			sleepTime(10000L);
			getHtmlContentByCompDetailUrl(compDetailUrl);
		}
		return result;
	}
	
	//通过get请求和参数获取招投标信息
	private List<CompBidding> getHtmlContentByParamAndKeyNo(String param,String keyNo,Long compId,String compName,Integer totalPage) {
		List<CompBidding> compBiddingList = new ArrayList<CompBidding>();
		//标识是否爬到了指定日期，默认false
		boolean flag = false;
		for (int i = 0; i < totalPage; i++) {
			//flag=true标识已经爬取到了指定日期
			if (flag) {
				break;
			}
			//每次循环 休眠10s
			sleepTime(10001L);
			//当前页码
			int p = i+1;
//			System.out.println("当前准备爬取第"+ p +"条数据！");
			//当爬取完500页就跳出循环
			if (p == 501) {
				break;
			}
			//招投标第p页的请求链接
			String visitUrl = url+param+"?unique="+keyNo+"&companyname="+compName+"&p="+p+"&tab=run&box=tender";
			//爬取结果
			String result = "";
			try {
				io.github.biezhi.elves.ok.http.Response okHttpResponse;
				okHttpResponse = FastHttpClient
						.newBuilder()
						.build()
						.get()
						.addHeader("cookie", qccCookie)
						.addHeader("Referer", "https://www.qcc.com/firm_"+ keyNo +".html")
						.url(visitUrl)
						.build()
						.execute();
				result = okHttpResponse.string();
				if (result.contains("<script>window.location.href='https://www.qcc.com/")
						|| result.contains("user_login_normal")) {
					System.err.println("获取招投标title过于频繁，休眠30s！" + Thread.currentThread().getName()+"========>"+qccCookie);
					sleepTime(30000L);
					return getHtmlContentByParamAndKeyNo(param,keyNo,compId,compName,totalPage);
				}else {
					Document doc = Jsoup.parse(result);
					Elements bidtitleUrls = doc.select("table.ntable.ntable-odd > tbody > tr");
					//删除<th>那一行
					bidtitleUrls.remove(0);
					List<CompBidding> compBidListByPage = new ArrayList<CompBidding>();
					for (Element bidtitleUrl : bidtitleUrls) {
						CompBidding compBidding = new CompBidding();
						String biddingTitleUrl = bidtitleUrl.select("td").get(1).select("a").attr("href");
						String biddingTitle = bidtitleUrl.select("td").get(1).select("a").text();
						//爬取下来的日期2020-01-18，转换成20200118
						String dateStr = bidtitleUrl.select("td").get(2).text().replace("-", "").trim();
						int date = 0;  
						if (dateStr != null && !dateStr.equals("")) {
							date = Integer.parseInt(dateStr);
						}
						//当爬到小于20200101这个日期后，就停止插入，更新标识flag为true,并跳出循环
						if (date < 20200101) {
							flag = true;
							break;
						}
						compBidding.setCompId(compId);
						compBidding.setCompName(compName);
						compBidding.setBiddingTitle(biddingTitle);
						compBidding.setBiddingTitleUrl(biddingTitleUrl);
						compBidListByPage.add(compBidding);
					}
					compBiddingList.addAll(compBidListByPage);
				}
				
			} catch (SocketTimeoutException e) {
				System.err.println("===连接超时，重新调用getHtmlContentByParamAndKeyNo(param,keyNo,compId,compName,totalPage)方法===");
				sleepTime(10000L);
				return getHtmlContentByParamAndKeyNo(param,keyNo,compId,compName,totalPage);
			} catch (Exception e) {
				e.printStackTrace();
				System.err.println("===其他异常，重新调用getHtmlContentByParamAndKeyNo(param,keyNo,compId,compName,totalPage)方法===");
				sleepTime(10000L);
				return getHtmlContentByParamAndKeyNo(param,keyNo,compId,compName,totalPage);
			}
			
		}
		
		return compBiddingList;
	}
	
	//通过get请求和参数获取招投标总数
	private Integer getHtmlContentByParamAndKeyNo(String param,String keyNo,Long compId,String compName) {
		//设置当前页码为1
		int p = 1;
		//招投标第p页的请求链接
		String visitUrl = url+param+"?unique="+keyNo+"&companyname="+compName+"&p="+p+"&tab=run&box=tender";
		//爬取结果
		String result = "";
		//招投标数量
		Integer totalCount = 0;
		try {
			io.github.biezhi.elves.ok.http.Response okHttpResponse;
			okHttpResponse = FastHttpClient
					.newBuilder()
					.build()
					.get()
					.addHeader("cookie", qccCookie)
					.addHeader("Referer", "https://www.qcc.com/firm_"+ keyNo +".html")
					.url(visitUrl)
					.build()
					.execute();
			result = okHttpResponse.string();
			if (result.contains("<script>window.location.href='https://www.qcc.com/")
					|| result.contains("user_login_normal")) {
				System.err.println("请求获取招投标总数过于频繁，休眠30s！" + Thread.currentThread().getName()+"========>"+qccCookie);
				sleepTime(30000L);
				return getHtmlContentByParamAndKeyNo(param,keyNo,compId,compName);
			}else {
				Document doc = Jsoup.parse(result);
				Elements elements = doc.select(".tcaption > .tbadge");
				System.out.println(elements);
				if (elements.size()==0) {
					return totalCount;
				}else {
					String totalCountStr = doc.select(".tcaption > .tbadge").get(0).text();
					if (totalCountStr != null && !totalCountStr.equals("")) {
						totalCount = Integer.valueOf(totalCountStr);
					}
				}
				return totalCount;
			}
			
		} catch (SocketTimeoutException e) {
			System.err.println("===连接超时，重新调用getHtmlContentByParamAndKeyNo(param,keyNo,compId,compName)方法===");
			sleepTime(10000L);
			return getHtmlContentByParamAndKeyNo(param,keyNo,compId,compName);
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("===其他异常，重新调用getHtmlContentByParamAndKeyNo(param,keyNo,compId,compName)方法===");
			sleepTime(10000L);
			return getHtmlContentByParamAndKeyNo(param,keyNo,compId,compName);
		}
	}
		
	//休眠
	private void sleepTime(Long sleepTime) {
		try {
			Thread.sleep(sleepTime);
			System.err.println("休眠" + sleepTime + "毫秒后，往下执行");
		} catch (Exception e){}
	}
	
	private void resetProxyIp() {
		try{
			Map<String,Object> proxyIpMap = StringUtils.getHttpProxyIp(1);
			String proxyJson = JSONObject.toJSONString(proxyIpMap);
			System.out.println(proxyJson);
			proxyIp = StringUtils.getValueForKey("proxyHost", proxyIpMap);
			proxyPort = StringUtils.getIntValueForKey("proxyPort", proxyIpMap);
			
			System.out.println("代理ip{{}}==>" + proxyIp + "，代理端口{{}}==>" + proxyPort);
		} catch (Exception e) {
			System.err.println("获取第三方代理ip接口异常{{}}==>" + StringUtils.getErrorInfoFromException(e));
		}
	}

	/**
	 * 获取公司详情页面的url
	 * @param result 通过getHtmlContentByCompName爬取出来的的页面
	 * @return 公司详情页面的url
	 */
	public CompBasic getCompDetailUrl(String result){
		CompBasic compBasic = new CompBasic();
		Document doc = Jsoup.parse(result);
		Elements allAElements = doc.select("a.ma_h1");
		ListIterator<Element> htmlAResultIter = allAElements.listIterator();
		//取搜索到的排第一家的企业
		if (htmlAResultIter.hasNext()) {
			Element element = (Element) htmlAResultIter.next();
			String compDetailUrl = element.attr("href");
			String compName = element.text();
			compBasic.setCompName(compName);
			compBasic.setCompDetailUrl(compDetailUrl);
			return compBasic;
		}
		return compBasic;
	}
	
	public static void main(String[] args) {
		String visitUrl = "https://www.qcc.com/company_getinfos?unique=de7bfce7f9814421f424e0a5decd6ed9&companyname=广东天黎科盛信息技术有限公司&p=1&tab=run&box=tender";
		//爬取结果
		String result = "";
			io.github.biezhi.elves.ok.http.Response okHttpResponse;
			try {
				okHttpResponse = FastHttpClient
						.newBuilder()
						.build()
						.get()
						.addHeader("cookie", "QCCSESSID=jpsim9upk1mpmtf7bu023rfcn7; zg_did=%7B%22did%22%3A%20%2216f308c5a6c120-096498f0382a08-32365f08-100200-16f308c5a6def%22%7D; UM_distinctid=16f308c5b1c1c0-0a9218e3ffdb1e-32365f08-100200-16f308c5b1d321; _uab_collina=157706750263744272271734; acw_tc=0e117c2015770675027168129e3a8f4a59719a716592dde533e1b1130b; hasShow=1; Hm_lvt_3456bee468c83cc63fb5147f119f1075=1577259644,1577324443,1577408991,1577415757; CNZZDATA1254842228=1218463662-1577066170-https%253A%252F%252Fwww.baidu.com%252F%7C1577436404; Hm_lpvt_3456bee468c83cc63fb5147f119f1075=1577439813; zg_de1d1a35bfa24ce29bbf2c7eb17e6c4f=%7B%22sid%22%3A%201577439638333%2C%22updated%22%3A%201577439830340%2C%22info%22%3A%201577067502211%2C%22superProperty%22%3A%20%22%7B%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22www.qcc.com%22%2C%22cuid%22%3A%20%22e5bc84c359aecc019d53c61a36dd33f9%22%2C%22zs%22%3A%200%2C%22sc%22%3A%200%7D")
						.addHeader("Referer", "https://www.qcc.com/firm_de7bfce7f9814421f424e0a5decd6ed9.html")
						.url(visitUrl)
						.build()
						.execute();
				result = okHttpResponse.string();
//				System.out.println(result);
				Document doc = Jsoup.parse(result);
				Integer totalCount = 0;
				String totalCountStr = doc.select(".tcaption > .tbadge").get(0).text();
				if (totalCountStr != null && !totalCountStr.equals("")) {
					totalCount = Integer.valueOf(totalCountStr);
				}
				System.out.println(totalCount);
				Integer totalPage = (int) Math.ceil(totalCount / 10);
				System.out.println(totalPage);
			} catch (Exception e) {
				e.printStackTrace();
			}
//			System.out.println(result);
	}
}
